package com.study.java._01generic;

import java.util.List;

/**
 * <pre>
 *     author : slx
 *     time   : 2020/11/17
 *     desc   : 泛型定义
 * </pre>
 */
class _02Demo {
    public static void main(String[] args) {
        // 原始类型：缺少实际类型变量的泛型
        Box box = new Box();
        // Java泛型为伪泛型，在运行时擦除，虚拟机不支持泛型，为了兼容，可以将参数化类型分配给原始类型
        Box<String> sBox = new Box<>();
        box = sBox;
        // 如果将原始类型赋值给参数化类型会警告 unchecked conversion
        sBox = new Box();

        // 调用泛型方法,泛型可以推断出来
        Box.<Double>test2(2.0, 3.0);

        // test3接收Number类型，传入int、double都可以
        sBox.test3(12.0);
        sBox.test3(1f);

        // test4接收Box<Number>类型，传入Box<Double>编译报错
        // 虽然Double是Number子类，但是Box<Number>、Box<Double>无关
        //sBox.test4(new Box<Double>());
    }
}

// 泛型类、接口,可以定义多个类型
interface Generics<T, S> {
}

// 泛型继承、实现
// T,S为类型参数，String,Double 为类型变量
class GenericsImpl<T, S> implements Generics<T, S> {
    public static void main(String[] args) {
        // 实例化时填写具体类型
        GenericsImpl<String, Double> g = new GenericsImpl<>();
    }
}

class GenericsImpl2 implements Generics<String, Integer> {
    public static void main(String[] args) {
        // 在实现接口时直接声明参数类型
        GenericsImpl2 g = new GenericsImpl2();
    }
}

// 泛型方法
class Box<T> {
    private T t;

    // 不是泛型方法
    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    // 泛型方法,泛型方法的类型参数和类的类型参数无关
    public <U> U test(U u) {
        return u;
    }

    // 限定类型参数,通过类型限定可以直接调用参数的方法
    public static <N extends Comparable<N>> void test2(N n1, N n2) {
        // 不能直接使用n1>n2,因为n1、n2是对象，>仅适用于基本类型
        if (n1.compareTo(n2) > 0) {
            System.out.println("n1>n2");
        }
    }

    // 继承与子类型
    public void test3(Number n) {

    }

    public void test4(Box<Number> box) {

    }
}

// 子类型：ArrayList<E> 实现了 List<E> 则ArrayList<E>是List的子类型
// 只要不改变类型参数，子类型就保留在类型之间,当然也可以添加类型参数
interface MyList<E, P> extends List<E> {

}


// 多类型限定，类型使用&隔开而且类必须在第一位
class A {
}

interface B {
}

class D<T extends A & B> {
}
